home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / bin / tasksel < prev    next >
Text File  |  2008-10-10  |  20KB  |  796 lines

  1. #!/usr/bin/perl
  2. # Debian task selector, mark II.
  3. # Copyright 2004-2006 by Joey Hess <joeyh@debian.org>.
  4. # Licensed under the GPL, version 2 or higher.
  5. use Locale::gettext;
  6. use Getopt::Long;
  7. use POSIX qw(floor);
  8. use warnings;
  9. use strict;
  10. textdomain('tasksel');
  11.  
  12. my $debconf_helper="/usr/lib/tasksel/tasksel-debconf";
  13. my $filter_tasks="/usr/lib/tasksel/filter-tasks";
  14. my $testdir="/usr/lib/tasksel/tests";
  15. my $packagesdir="/usr/lib/tasksel/packages";
  16. my $descdir="/usr/share/tasksel";
  17. my $localdescdir="/usr/local/share/tasksel";
  18. my $statusfile="/var/lib/dpkg/status";
  19. my $infodir="/usr/lib/tasksel/info";
  20. my $testmode=0;
  21.  
  22. sub warning {
  23.     print STDERR "tasksel: @_\n";
  24. }
  25.  
  26. sub error {
  27.     print STDERR "tasksel: @_\n";
  28.     exit 1;
  29. }
  30.  
  31. # Run a shell command except in test mode, and returns its exit code.
  32. # Prints the command in test mode. Parameters should be pre-split for
  33. # system.
  34. sub run {
  35.     if ($testmode) {
  36.         print join(" ", @_)."\n";
  37.         return 0;
  38.     }
  39.     else {
  40.         return system(@_) >> 8;
  41.     }
  42. }
  43.  
  44. # A list of all available task desc files.
  45. sub list_task_descs {
  46.     return glob("$descdir/*.desc"), glob("$localdescdir/*.desc");
  47. }
  48.  
  49. # Returns a list of hashes; hash values are arrays for multi-line fields.
  50. sub read_task_desc {
  51.     my $desc=shift;
  52.     my @ret;
  53.     open (DESC, "<$desc") || die "read $desc\: $!";
  54.     local $/="\n\n";
  55.     while (<DESC>) {
  56.         my %data;
  57.         my @lines=split("\n");
  58.         while (@lines) {
  59.             my $line=shift(@lines);
  60.             if ($line=~/^([^ ]+):(?: (.*))?/) {
  61.                 my ($key, $value)=($1, $2);
  62.                 $key=lc($key);
  63.                 if (@lines && $lines[0] =~ /^\s+/) {
  64.                     # multi-line field
  65.                     my @values;
  66.                     if (defined $value && length $value) {
  67.                         push @values, $value;
  68.                     }
  69.                     while (@lines && $lines[0] =~ /^\s+(.*)/) {
  70.                         push @values, $1;
  71.                         shift @lines;
  72.                     }
  73.                     $data{$key}=[@values];
  74.                 }
  75.                 else {
  76.                     $data{$key}=$value;
  77.                 }
  78.             }
  79.             else {
  80.                 warning "parse error in stanza $. of $desc";
  81.             }
  82.         }
  83.         if (%data) {
  84.             $data{relevance}=5 unless exists $data{relevance};
  85.             $data{shortdesc}=$data{description}->[0];
  86.             $data{shortdesctrans}=dgettext("debian-tasks", $data{shortdesc});
  87.             push @ret, \%data;
  88.         }
  89.     }
  90.     close DESC;
  91.     return @ret;
  92. }
  93.  
  94. # Loads info for all tasks, and returns a set of task structures.
  95. sub all_tasks {
  96.     my %seen;
  97.     grep { $seen{$_->{task}}++; $seen{$_->{task}} < 2 }
  98.     map { read_task_desc($_) } list_task_descs();
  99. }
  100.  
  101. # Returns a list of all available packages.
  102. sub list_avail {
  103.     my @list;
  104.     # Might be better to use the perl apt bindings, but they are not
  105.     # currently in base.
  106.     open (AVAIL, "apt-cache dumpavail|");
  107.     local $_;
  108.     while (<AVAIL>) {
  109.         chomp;
  110.         if (/^Package: (.*)/) {
  111.             push @list, $1;
  112.         }
  113.     }
  114.     close AVAIL;
  115.     return @list;
  116. }
  117.  
  118. # Returns a list of all installed packages.
  119. sub list_installed {
  120.     my @list;
  121.     local $/="\n\n";
  122.     open (STATUS, $statusfile);
  123.     local $_;
  124.     while (<STATUS>) {
  125.         if (/^Status: .* installed$/m && /Package: (.*)$/m) {
  126.             push @list, $1;
  127.         }
  128.     }
  129.     close STATUS;
  130.     return @list;
  131. }
  132.  
  133. my %avail_pkgs;
  134. # Given a package name, checks to see if it's available. Memoised.
  135. sub package_avail {
  136.     my $package=shift;
  137.     
  138.     if (! %avail_pkgs) {
  139.         foreach my $pkg (list_avail()) {
  140.             $avail_pkgs{$pkg} = 1;
  141.         }
  142.     }
  143.  
  144.     return $avail_pkgs{$package} || package_installed($package);
  145. }
  146.  
  147. my %installed_pkgs;
  148. # Given a package name, checks to see if it's installed. Memoised.
  149. sub package_installed {
  150.     my $package=shift;
  151.     
  152.     if (! %installed_pkgs) {
  153.         foreach my $pkg (list_installed()) {
  154.             $installed_pkgs{$pkg} = 1;
  155.         }
  156.     }
  157.  
  158.     return $installed_pkgs{$package};
  159. }
  160.  
  161. # Given a task hash, checks if its key packages are available.
  162. sub task_avail {
  163.     local $_;
  164.     my $task=shift;
  165.     if (! ref $task->{key}) {
  166.         return 1;
  167.     }
  168.     else {
  169.         foreach my $pkg (@{$task->{key}}) {
  170.             if (! package_avail($pkg)) {
  171.                 return 0;
  172.             }
  173.         }
  174.         return 1;
  175.     }
  176. }
  177.  
  178. # Given a task hash, checks to see if it is already installed.
  179. # (All of its key packages must be installed.)
  180. sub task_installed {
  181.     local $_;
  182.     my $task=shift;
  183.     if (! ref $task->{key}) {
  184.         return 0; # can't tell with no key packages
  185.     }
  186.     else {
  187.         foreach my $pkg (@{$task->{key}}) {
  188.             if (! package_installed($pkg)) {
  189.                 return 0;
  190.             }
  191.         }
  192.         return 1;
  193.     }
  194. }
  195.  
  196. # Given task hash, returns a list of all available packages in the task.
  197. # If the apt_get_tasks parameter is true, then it does not expand tasks
  198. # that apt-get knows about, and just returns apt-get task syntax for
  199. # those.
  200. sub task_packages {
  201.     my $task=shift;
  202.     my $apt_get_tasks=shift;
  203.     
  204.     my %list;
  205.  
  206.     # key packages are always included
  207.     if (ref $task->{key}) {
  208.         map { $list{$_}=1 } @{$task->{key}};
  209.     }
  210.         
  211.     if ($task->{packages} eq 'task-fields') {
  212.         # task-fields method is built-in for speed and to support
  213.         # apt-get task definitions
  214.         if ($apt_get_tasks) {
  215.             return $task->{task}.'^';
  216.         }
  217.         else {
  218.             local $/="\n\n";
  219.             open (AVAIL, "apt-cache dumpavail|");
  220.             while (<AVAIL>) {
  221.                 if (/^Task: (.*)/m) {
  222.                     my @tasks=split(", ", $1);
  223.                     if (grep { $_ eq $task->{task} } @tasks) { 
  224.                         $list{$1}=1 if /^Package: (.*)/m;
  225.                     }
  226.                 }
  227.             }
  228.             close AVAIL;
  229.         }
  230.     }
  231.     elsif ($task->{packages} eq 'standard') {
  232.         # standard method is built in since it cannot easily be
  233.         # implemented externally.
  234.         #return "~pstandard", "~prequired", "~pimportant";
  235.         # Unfortunately, this needs aptitude, not apt-get, and we
  236.         # have to use apt-get for other reasons ...
  237.         die "'Packages: standard' not supported by this version of tasksel\n";
  238.     }
  239.     elsif ($task->{packages} eq 'manual') {
  240.         # manual package selection is a special case
  241.         return;
  242.     }
  243.     else {
  244.         # external method
  245.         my ($method, @params);
  246.         if (ref $task->{packages}) {
  247.             @params=@{$task->{packages}};
  248.             $method=shift @params;
  249.         }
  250.         else {
  251.             $method=$task->{packages};
  252.         }
  253.         
  254.         map { $list{$_}=1 }
  255.             grep { package_avail($_) }
  256.             split(' ', `$packagesdir/$method $task->{task} @params`);
  257.     }
  258.  
  259.     return keys %list;
  260. }
  261.  
  262. # Given a list of task hashes, adjust their statuses according to
  263. # tasksel/force-tasks, tasksel/limit-tasks, and tasksel/skip-tasks.
  264. sub filter_tasks {
  265.     my %tasks=map { $_->{task} => $_ } @_;
  266.     my $tmpfile=`tempfile`;
  267.     chomp $tmpfile;
  268.     my $ret=system($filter_tasks, $tmpfile, sort keys %tasks) >> 8;
  269.     if ($ret != 0) {
  270.         error "filter-tasks failed to run";
  271.     }
  272.     open(IN, "<$tmpfile") or return;
  273.     for my $line (<IN>) {
  274.         chomp $line;
  275.         $line=~/(.*?) (install|skip)/ or next;
  276.         my $name=$1;
  277.         my $action=$2;
  278.         if ($action eq 'install') {
  279.             $tasks{$name}{_display} = 0;
  280.             $tasks{$name}{_install} = 1;
  281.         }
  282.         elsif ($action eq 'skip') {
  283.             $tasks{$name}{_display} = 0;
  284.             $tasks{$name}{_install} = 0;
  285.         }
  286.     }
  287.     close IN;
  288.     unlink $tmpfile;
  289. }
  290.  
  291. # Given a task hash, runs any test program specified in its data, and sets
  292. # the _display and _install fields to 1 or 0 depending on its result.
  293. sub task_test {
  294.     my $task=shift;
  295.     my $new_install=shift;
  296.     $task->{_display} = shift; # default
  297.     $task->{_install} = shift; # default
  298.     $ENV{NEW_INSTALL}=$new_install if defined $new_install;
  299.     foreach my $test (grep /^test-.*/, keys %$task) {
  300.         $test=~s/^test-//;
  301.         if (-x "$testdir/$test") {
  302.             my $ret=system("$testdir/$test", $task->{task}, split " ", $task->{"test-$test"}) >> 8;
  303.             if ($ret == 0) {
  304.                 $task->{_display} = 0;
  305.                 $task->{_install} = 1;
  306.             }
  307.             elsif ($ret == 1) {
  308.                 $task->{_display} = 0;
  309.                 $task->{_install} = 0;
  310.             }
  311.             elsif ($ret == 2) {
  312.                 $task->{_display} = 1;
  313.                 $task->{_install} = 1;
  314.             }
  315.             elsif ($ret == 3) {
  316.                 $task->{_display} = 1;
  317.                 $task->{_install} = 0;
  318.             }
  319.         }
  320.     }
  321.     
  322.     delete $ENV{NEW_INSTALL};
  323.     return $task;
  324. }
  325.  
  326. # Hides a task and marks it not to be installed if it enhances other
  327. # tasks.
  328. sub hide_enhancing_tasks {
  329.     my $task=shift;
  330.     if (exists $task->{enhances} && length $task->{enhances}) {
  331.         $task->{_display} = 0;
  332.         $task->{_install} = 0;
  333.     }
  334.     return $task;
  335. }
  336.  
  337. # Converts a list of tasks into a debconf list of their short descriptions.
  338. sub task_to_debconf {
  339.     my $field = shift;
  340.     join ", ", map {
  341.         my $desc=$_->{$field};
  342.         if ($desc=~/, /) {
  343.             warning("task ".$_->{task}." contains a comma in its short description: \"$desc\"");
  344.         }
  345.         $desc;
  346.     } @_;
  347. }
  348.  
  349. # Given a first parameter that is a debconf list of short descriptions of
  350. # tasks, or a dependency style list of task names, and then a list of task
  351. # hashes, returns a list of hashes for all the tasks in the list.
  352. sub list_to_tasks {
  353.     my $list=shift;
  354.     my %desc_to_task = map { $_->{shortdesc} => $_, $_->{task} => $_ } @_;
  355.     return grep { defined } map { $desc_to_task{$_} } split ", ", $list;
  356. }
  357.  
  358. # Orders a list of tasks for display.
  359. sub order_for_display {
  360.     sort {
  361.         $b->{relevance} <=> $a->{relevance}
  362.                       || 0 ||
  363.           $a->{section} cmp $b->{section}
  364.                       || 0 ||
  365.             $a->{shortdesc} cmp $b->{shortdesc}
  366.     } @_;
  367. }
  368.  
  369. # Given a set of tasks and a name, returns the one with that name.
  370. sub name_to_task {
  371.     my $name=shift;
  372.     return (grep { $_->{task} eq $name } @_)[0];
  373. }
  374.  
  375. sub find_task_script {
  376.     my $task=shift;
  377.     my $script=shift;
  378.  
  379.     my $path="$infodir/$task.$script";
  380.     if (-e $path && -x _) {
  381.         return $path;
  382.     } else {
  383.         return undef;
  384.     }
  385. }
  386.  
  387. sub run_task_script {
  388.     my $path=pop;
  389.     my @prefix=@_;
  390.  
  391.     my $ret=run(@prefix, $path);
  392.     if ($ret != 0) {
  393.         warning("$path exited with nonzero code $ret");
  394.         return 0;
  395.     }
  396.     return 1;
  397. }
  398.  
  399. sub debconf_apt_command {
  400.     my $dap=shift;
  401.     my $from=shift;
  402.     my $to=shift;
  403.     my $options=shift;
  404.  
  405.     my @cmd=($dap, '--from', $from, '--to', $to);
  406.     push @cmd, @$options if defined $options;
  407.     push @cmd, '--';
  408.     return @cmd;
  409. }
  410.  
  411. # Works out the region of a progress bar needed for a given invocation of
  412. # debconf-apt-progress, and returns the appropriate debconf-apt-progress
  413. # command.
  414. sub task_region {
  415.     my $dap=shift;
  416.     my $start=shift;
  417.     my $end=shift;
  418.     my $options=shift;
  419.     my $cur_region=shift;
  420.     my $step_region=shift;
  421.     my $num_regions=shift;
  422.  
  423.     if (defined $start and defined $end and $num_regions) {
  424.         my $from=floor($start + ($end - $start) * $cur_region / $num_regions + 0.5);
  425.         my $to=floor($start + ($end - $start) * ($cur_region + $step_region) / $num_regions + 0.5);
  426.         return debconf_apt_command($dap, $from, $to, $options);
  427.     } else {
  428.         return;
  429.     }
  430. }
  431.  
  432. sub usage {
  433.     print STDERR gettext(q{Usage:
  434. tasksel install <task>
  435. tasksel remove <task>
  436. tasksel [options]
  437.     -t, --test          test mode; don't really do anything
  438.         --new-install   automatically install some tasks
  439.         --list-tasks    list tasks that would be displayed and exit
  440.         --task-packages list available packages in a task
  441.         --task-desc     returns the description of a task
  442. });
  443. }
  444.  
  445. # Process command line options and return them in a hash.
  446. sub getopts {
  447.     my %ret;
  448.     Getopt::Long::Configure ("bundling");
  449.     if (! GetOptions(\%ret, "test|t", "new-install", "list-tasks",
  450.            "task-packages=s@", "task-desc=s",
  451.            "section=s",
  452.            "debconf-apt-from=i", "debconf-apt-to=i",
  453.            "debconf-apt-progress=s")) {
  454.         usage();
  455.         exit(1);
  456.     }
  457.     # Special case apt-like syntax.
  458.     if (@ARGV && $ARGV[0] eq "install") {
  459.         shift @ARGV;
  460.         $ret{install} = shift @ARGV;
  461.     }
  462.     if (@ARGV && $ARGV[0] eq "remove") {
  463.         shift @ARGV;
  464.         $ret{remove} = shift @ARGV;
  465.     }
  466.     if (@ARGV) {
  467.         usage();
  468.         exit 1;
  469.     }
  470.     $testmode=1 if $ret{test}; # set global
  471.     return %ret;
  472. }
  473.  
  474. sub main {
  475.     my %options=getopts();
  476.     my @tasks_remove;
  477.     my @tasks_install;
  478.  
  479.     # Options that output stuff and don't need a full processed list of
  480.     # tasks.
  481.     if (exists $options{"task-packages"}) {
  482.         my @tasks=all_tasks();
  483.         foreach my $taskname (@{$options{"task-packages"}}) {
  484.             my $task=name_to_task($taskname, @tasks);
  485.             if ($task) {
  486.                 print "$_\n" foreach task_packages($task);
  487.             }
  488.         }
  489.         exit(0);
  490.     }
  491.     elsif ($options{"task-desc"}) {
  492.         my $task=name_to_task($options{"task-desc"}, all_tasks());
  493.         if ($task) {
  494.             my $extdesc=join(" ", @{$task->{description}}[1..$#{$task->{description}}]);
  495.             print dgettext("debian-tasks", $extdesc)."\n";
  496.             exit(0);
  497.         }
  498.         else {
  499.             exit(1);
  500.         }
  501.     }
  502.  
  503.     # This is relatively expensive, get the full list of available tasks and
  504.     # mark them.
  505.     my @tasks=map { hide_enhancing_tasks($_) } map { task_test($_, $options{"new-install"}, 1, 0) }
  506.               grep { task_avail($_) } all_tasks();
  507.     if ($options{"new-install"}) {
  508.         filter_tasks(@tasks);
  509.     }
  510.     
  511.     # Limit the tasks shown to a single section
  512.     if ($options{section}) { 
  513.         @tasks = grep { $options{section} eq $_->{section} } @tasks; 
  514.     }
  515.  
  516.     if ($options{"list-tasks"}) {
  517.         map { $_->{_installed} = task_installed($_) } @tasks;
  518.         print "".($_->{_installed} ? "i" : "u")." ".$_->{task}."\t".$_->{shortdesc}."\n"
  519.             foreach order_for_display(grep { $_->{_display} } @tasks);
  520.         exit(0);
  521.     }
  522.     
  523.     if (! $options{"new-install"}) {
  524.         # Don't install hidden tasks if this is not a new install.
  525.         map { $_->{_install} = 0 } grep { $_->{_display} == 0 } @tasks;
  526.     }
  527.     if ($options{"install"}) {
  528.         my $task=name_to_task($options{"install"}, @tasks);
  529.         $task->{_install} = 1 if $task;
  530.     }
  531.     if ($options{"remove"}) {
  532.         my $task=name_to_task($options{"remove"}, @tasks);
  533.         push @tasks_remove, $task;
  534.     }
  535.     
  536.     # The interactive bit.
  537.     my $interactive=0;
  538.     my @list = order_for_display(grep { $_->{_display} == 1 } @tasks);
  539.     if (@list && ! $options{install} && ! $options{remove}) {
  540.         $interactive=1;
  541.         if (! $options{"new-install"}) {
  542.             # Find tasks that are already installed.
  543.             map { $_->{_installed} = task_installed($_) } @list;
  544.             # Don't install new tasks unless manually selected.
  545.             map { $_->{_install} = 0 } @list;
  546.         }
  547.         else {
  548.             # Assume that no tasks are installed, to ensure
  549.             # that complete tasks get installed on new
  550.             # installs.
  551.             map { $_->{_installed} = 0 } @list;
  552.         }
  553.         my $question="tasksel/tasks";
  554.         if ($options{"new-install"}) {
  555.             $question="tasksel/first";
  556.         }
  557.         my @default = grep { $_->{_display} == 1 && ($_->{_install} == 1 || $_->{_installed} == 1) } @tasks;
  558.         my $tmpfile=`tempfile`;
  559.         chomp $tmpfile;
  560.  
  561.         # Canonicalise $question's value first, so that it will be
  562.         # displayed properly if preseeded unseen.
  563.         my $ret=system($debconf_helper, "--get", $tmpfile,
  564.             $question) >> 8;
  565.         if ($ret != 0) {
  566.             error "debconf failed to run";
  567.         }
  568.         open(IN, "<$tmpfile");
  569.         $ret=<IN>;
  570.         if (! defined $ret) {
  571.             die "tasksel canceled\n";
  572.         }
  573.         chomp $ret;
  574.         close IN;
  575.  
  576.         if ($ret ne "") {
  577.             my $new_value = task_to_debconf("shortdesc",
  578.                 list_to_tasks($ret, @list));
  579.             $ret=system($debconf_helper, "--set", $question,
  580.                 $new_value) >> 8;
  581.             if ($ret != 0) {
  582.                 error "debconf failed to run";
  583.             }
  584.         }
  585.  
  586.         $ret=system($debconf_helper, $tmpfile,
  587.             task_to_debconf("shortdesc", @list),
  588.             task_to_debconf("shortdesctrans", @list),
  589.             task_to_debconf("shortdesc", @default),
  590.             $question) >> 8;
  591.         if ($ret == 30) {
  592.             exit 10; # back up
  593.         }
  594.         elsif ($ret != 0) {
  595.             error "debconf failed to run";
  596.         }
  597.         open(IN, "<$tmpfile");
  598.         $ret=<IN>;
  599.         if (! defined $ret) {
  600.             die "tasksel canceled\n";
  601.         }
  602.         chomp $ret;
  603.         close IN;
  604.         unlink $tmpfile;
  605.         
  606.         # Set _install flags based on user selection.
  607.         map { $_->{_install} = 0 } @list;
  608.         foreach my $task (list_to_tasks($ret, @tasks)) {
  609.             if (! $task->{_installed}) {
  610.                 $task->{_install} = 1;
  611.             }
  612.             $task->{_selected} = 1;
  613.         }
  614.         foreach my $task (@list) {
  615.             if (! $task->{_selected} && $task->{_installed}) {
  616.                 push @tasks_remove, $task;
  617.             }
  618.         }
  619.     }
  620.  
  621.     # If an enhancing task is already marked for
  622.     # install, probably by preseeding, mark the tasks
  623.     # it enhances for install.
  624.     foreach my $task (grep { $_->{_install} && exists $_->{enhances} &&
  625.                              length $_->{enhances} } @tasks) {
  626.         map { $_->{_install}=1 } list_to_tasks($task->{enhances}, @tasks);
  627.     }
  628.  
  629.     # Select enhancing tasks for install.
  630.     # XXX FIXME ugly hack -- loop until enhances settle to handle
  631.     # chained enhances. This is sloow and could loop forever if
  632.     # there's a cycle.
  633.     my $enhances_needswork=1;
  634.     while ($enhances_needswork) {
  635.         $enhances_needswork=0;
  636.         foreach my $task (grep { ! $_->{_install} && exists $_->{enhances} &&
  637.                                  length $_->{enhances} } @tasks) {
  638.             my @deps=list_to_tasks($task->{enhances}, @tasks);
  639.             if (@deps) {
  640.                 my $orig_state=$task->{_install};
  641.  
  642.                 # Mark enhancing tasks for install if their
  643.                 # dependencies are met and their test fields
  644.                 # mark them for install.
  645.                 $ENV{TESTING_ENHANCER}=1;
  646.                 task_test($task, $options{"new-install"}, 0, 1);
  647.                 delete $ENV{TESTING_ENHANCER};
  648.                 foreach my $dep (@deps) {
  649.                     if (! $dep->{_install}) {
  650.                         $task->{_install} = 0;
  651.                     }
  652.                 }
  653.  
  654.                 if ($task->{_install} != $orig_state) {
  655.                     $enhances_needswork=1;
  656.                 }
  657.             }
  658.         }
  659.     }
  660.  
  661.     # Add tasks to install and see if any selected task requires manual
  662.     # selection.
  663.     my $manual_selection=0;
  664.     foreach my $task (grep { $_->{_install} } @tasks) {
  665.         push @tasks_install, $task;
  666.         if ($task->{packages} eq 'manual') {
  667.             if (-x "/usr/bin/aptitude") {
  668.                 $manual_selection=1;
  669.             } else {
  670.                 warning "task $task requires aptitude";
  671.             }
  672.         }
  673.     }
  674.     
  675.     my $dap;
  676.     my ($dap_from, $dap_to);
  677.     my @dap_options;
  678.     my @apt;
  679.     my @no_recommends;
  680.     if ($manual_selection) {
  681.         # Manaul selection and task installs, as best
  682.         # aptitude can do it currently. Disables use of
  683.         # debconf-apt-progress.
  684.         @apt="aptitude";
  685.         @no_recommends=qw{--without-recommends -o APT::Install-Recommends=no};
  686.     }
  687.     elsif (-x "/usr/bin/debconf-apt-progress") {
  688.         $dap="debconf-apt-progress";
  689.         if (exists $options{'debconf-apt-from'} and
  690.             exists $options{'debconf-apt-to'}) {
  691.             $dap_from=$options{'debconf-apt-from'};
  692.             $dap_to=$options{'debconf-apt-to'};
  693.         }
  694.         push @dap_options, split(' ', $options{'debconf-apt-progress'})
  695.             if exists $options{'debconf-apt-progress'};
  696.         @apt=qw{apt-get -q};
  697.         @no_recommends="--no-install-recommends";
  698.     }
  699.     else {
  700.         @apt="apt-get";
  701.         @no_recommends="--no-install-recommends";
  702.     }
  703.  
  704.     # We arbitrarily allocate 5% of the progress bar to task scripts,
  705.     # divided equally among all the scripts. (If you change this, the
  706.     # new percentage should divide equally into 100.)
  707.     my $num_regions=0;
  708.     foreach my $task (@tasks_remove) {
  709.         if (defined find_task_script($task->{task}, "prerm")) {
  710.             ++$num_regions;
  711.         }
  712.         if (defined find_task_script($task->{task}, "postrm")) {
  713.             ++$num_regions;
  714.         }
  715.     }
  716.     foreach my $task (@tasks_install) {
  717.         if (defined find_task_script($task->{task}, "preinst")) {
  718.             ++$num_regions;
  719.         }
  720.         if (defined find_task_script($task->{task}, "postinst")) {
  721.             ++$num_regions;
  722.         }
  723.     }
  724.     $num_regions*=20;
  725.     my $cur_region=0;
  726.     
  727.     # And finally, act on selected tasks.
  728.     if (@tasks_install || @tasks_remove || $manual_selection) {
  729.         my @args;
  730.         foreach my $task (@tasks_remove) {
  731.             push @args, map { "$_-" } task_packages($task, 0);
  732.             my $path=find_task_script($task->{task}, "prerm");
  733.             if (defined $path) {
  734.                 my @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region++, 1, $num_regions);
  735.                 run_task_script(@prefix, $path);
  736.             }
  737.         }
  738.         foreach my $task (@tasks_install) {
  739.             push @args, task_packages($task, 1);
  740.             my $path=find_task_script($task->{task}, "preinst");
  741.             if (defined $path) {
  742.                 my @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region++, 1, $num_regions);
  743.                 run_task_script(@prefix, $path);
  744.             }
  745.         }
  746.         # If the user selected no other tasks and manual package
  747.         # selection, run aptitude w/o the --visual-preview parameter.
  748.         if (! @args && $manual_selection) {
  749.             my $ret=run("aptitude");
  750.             if ($ret != 0) {
  751.                 error gettext("aptitude failed")." ($ret)";
  752.             }
  753.         }
  754.         else {
  755.             if ($manual_selection) {
  756.                 unshift @args, "--visual-preview";
  757.             }
  758.             my @prefix;
  759.             if (defined $dap_from and defined $dap_to) {
  760.                 if ($num_regions) {
  761.                     # The main apt-get run takes up the
  762.                     # remaining 95% of the progress bar.
  763.                     @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region, $num_regions * 0.95, $num_regions);
  764.                     $cur_region=floor($cur_region + $num_regions * 0.95 + 0.5);
  765.                 } else {
  766.                     @prefix=debconf_apt_command($dap, $dap_from, $dap_to, \@dap_options);
  767.                 }
  768.             } elsif (defined $dap) {
  769.                 @prefix=($dap, @dap_options, '--');
  770.             }
  771.             my $ret=run(@prefix, @apt, @no_recommends,
  772.                                        "-y", "install",
  773.                                        @args);
  774.             if ($ret != 0) {
  775.                 error gettext("aptitude failed")." ($ret)";
  776.             }
  777.         }
  778.         foreach my $task (@tasks_remove) {
  779.             my $path=find_task_script($task->{task}, "postrm");
  780.             if (defined $path) {
  781.                 my @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region++, 1, $num_regions);
  782.                 run_task_script(@prefix, $path);
  783.             }
  784.         }
  785.         foreach my $task (@tasks_install) {
  786.             my $path=find_task_script($task->{task}, "postinst");
  787.             if (defined $path) {
  788.                 my @prefix=task_region($dap, $dap_from, $dap_to, \@dap_options, $cur_region++, 1, $num_regions);
  789.                 run_task_script(@prefix, $path);
  790.             }
  791.         }
  792.     }
  793. }
  794.  
  795. main();
  796.